#ifndef TIEC_TREE_PATH_H
#define TIEC_TREE_PATH_H

#include "tree.h"

namespace NS_TIEC {
  class TreePath {
  public:
    explicit TreePath(const PTR<TreePath>& parent, const PTR<Tree>& leaf);
    PTR<Tree> getLeaf() const;
    PTR<TreePath> getParent() const;

    static PTR<TreePath> getPath(const PTR<CompilationUnitTree>& root, const PTR<Tree>& target);
    static PTR<TreePath> getPath(const PTR<TreePath>& path, const PTR<Tree>& target);
  private:
    PTR<TreePath> parent_;
    PTR<Tree> leaf_;
  };

  template <typename Result, typename Param>
  class TreePathScanner : public TreeScanner<Result, Param> {
  public:
    explicit TreePathScanner(const PTR<TreePath>& path = nullptr) : path_(path) {
    }

    PTR<TreePath> getCurrentPath() const {
      return path_;
    }

    Result scanPath(const PTR<TreePath>& tree_path, Param param) {
      path_ = tree_path;
      return scan(path_->getLeaf(), param);
    }

    Result scan(const PTR<Tree>& tree, Param param) override {
      if (tree == nullptr) {
        if constexpr (std::is_void_v<Result>) {
          return;
        } else {
          return {};
        }
      }
      path_ = MAKE_PTR<TreePath>(path_, tree);
      return TreeScanner<Result, Param>::scan(tree, param);
    }
  private:
    PTR<TreePath> path_ {nullptr};
  };

  class TreePathSearcher : public TreePathScanner<PTR<TreePath>, const PTR<Tree>&> {
  public:
    PTR<TreePath> scan(const PTR<Tree>& tree, const PTR<Tree>& param) override {
      if (tree == param) {
        // 搜寻到匹配目标Tree的节点，不再继续扫描，直接返回TreePath
        return MAKE_PTR<TreePath>(getCurrentPath(), param);
      } else {
        return TreePathScanner<PTR<TreePath>, const PTR<Tree>&>::scan(tree, param);
      }
    }
  };
}

#endif
